package com.qqtech.web.context;

import java.io.IOException;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.slf4j.MDC;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import com.google.common.collect.Maps;
import com.google.common.collect.Sets;
import com.google.common.net.HttpHeaders;
import com.qqtech.core.common.annotation.VisitAnnt;
import com.qqtech.core.common.constant.CoreConst;
import com.qqtech.core.common.enums.RespEnum;
import com.qqtech.core.common.enums.YesNoEnum;
import com.qqtech.core.common.util.JsonUtil;
import com.qqtech.core.common.util.StringUtil;
import com.qqtech.core.common.util.TimeUtil;
import com.qqtech.core.frame.model.Result;
import com.qqtech.qquan.pub.model.PubUpgrade;
import com.qqtech.qquan.pub.model.PubUpgradeVo;
import com.qqtech.qquan.pub.service.PubUpgradeService;
import com.qqtech.qquan.user.enums.UserConst;
import com.qqtech.qquan.user.model.UserLoginVo;
import com.qqtech.qquan.user.service.UserLoginService;

public class WebInteceptor implements HandlerInterceptor {
	private static final Logger LOG = LoggerFactory.getLogger(WebInteceptor.class);
	private Set<String> allowUrls;
	private static final String VK_REQUEST_ID = "vkReqId";
	private Set<String> hiddenKeys = Sets.newHashSet("password", "pwd", "authToken", "token", "base64");

	@Resource
	private UserLoginService userLoginService;
	@Resource
	private PubUpgradeService pubUpgradeService;

	@Override
	public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object object, Exception ex)
			throws Exception {
		MDC.remove(VK_REQUEST_ID);
	}

	@Override
	public void postHandle(HttpServletRequest request, HttpServletResponse response, Object object, ModelAndView arg3)
			throws Exception {
	}

	@Override
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		String uri = request.getRequestURI();
		String requestUrl = uri.replace(request.getContextPath(), "");
		if (uri.indexOf("/res/") >= 0) {
			return true;
		}
		if (allowUrls != null && allowUrls.contains(requestUrl)) {
			return true;
		}
		if (!isLegalRequest(request)) {
			sendErrorMsg(response, RespEnum.ILLEGAL);
			return false;
		}
		/*
		Result result = handleUpgrade(request);
		if (result.checkForm()) {
			sendErrorMsg4Upgrade(response, RespEnum.UPGRADE, result);
			return false;
		}
		*/
		String userLoginToken = request.getHeader(UserConst.MAPKEY_USER_LOGIN_TOKEN);
		if (handler instanceof HandlerMethod) {
			VisitAnnt auth = ((HandlerMethod) handler).getMethod().getAnnotation(VisitAnnt.class);
			if (auth != null) {
				UserLoginVo userLoginVo = null;
				if (RespEnum.LOGIN.equals(auth.type()) || RespEnum.AUTHREAL.equals(auth.type())
						|| RespEnum.AUTHCOMMUNITY.equals(auth.type())) {
					if (StringUtil.isBlank(userLoginToken)) {
						sendErrorMsg(response, RespEnum.LOGIN);
						return false;
					}
					userLoginVo = userLoginService.getCacheByToken(userLoginToken);
					if (userLoginVo.getTokenExpireAt() == null
							|| TimeUtil.now().after(userLoginVo.getTokenExpireAt())) {
						sendErrorMsg(response, RespEnum.LOGIN);
						return false;
					}
				}
				if (RespEnum.AUTHREAL.equals(auth.type())) {
					if (StringUtil.isBlank(userLoginToken)) {
						sendErrorMsg(response, RespEnum.AUTHREAL);
						return false;
					} else {
						if (userLoginVo == null) {
							userLoginVo = userLoginService.getCacheByToken(userLoginToken);
						}
						if (userLoginVo.getHasIdentityAuth() == null
								|| YesNoEnum.YES.getCode() != userLoginVo.getHasIdentityAuth().intValue()) {
							sendErrorMsg(response, RespEnum.AUTHREAL);
							return false;
						}
					}
				}
				if (RespEnum.AUTHCOMMUNITY.equals(auth.type())) {
					if (StringUtil.isBlank(userLoginToken)) {
						sendErrorMsg(response, RespEnum.AUTHCOMMUNITY);
						return false;
					} else {
						if (userLoginVo == null) {
							userLoginVo = userLoginService.getCacheByToken(userLoginToken);
						}
						if (userLoginVo.getHasCommunityAuth() == null
								|| YesNoEnum.YES.getCode() != userLoginVo.getHasCommunityAuth().intValue()) {
							sendErrorMsg(response, RespEnum.AUTHCOMMUNITY);
							return false;
						}
					}
				}
			}
		}
		String reqId = buildRequestId();
		MDC.put(VK_REQUEST_ID, reqId);
		printRequest(request);
		return true;
	}

	/** 防止推送失效，多一个客户端升级方式 **/
	private Result handleUpgrade(HttpServletRequest request) {
		Result result = new Result();
		result.setCode(RespEnum.UPGRADE.getCode());
		PubUpgrade pubUpgrade = pubUpgradeService.getCurrentUpgrade();
		if (pubUpgrade == null || YesNoEnum.YES.getCode() != pubUpgrade.getIsUpgrade().intValue()
				|| YesNoEnum.YES.getCode() != pubUpgrade.getIsWebCheck().intValue()) {
			result.addErr("在web前端无有效的更新资源");
			return result;
		}
		String contentVer = request.getHeader("contentVer");
		String nativeVer = request.getHeader("nativeVer");
		String platformCodeStr = request.getHeader("platformCodeStr");
		if (StringUtil.isBlank(platformCodeStr)) {
			result.addErr("客户端系统不明");
			return result;
		}
		int platformCode = new Integer(platformCodeStr).intValue();
		result = pubUpgradeService.checkUpgrade(contentVer, nativeVer, platformCode);
		if (result.checkForm()) {
			result.setCode(RespEnum.UPGRADE.getCode());
			PubUpgradeVo pubUpgradeVo = (PubUpgradeVo) result.get("pubUpgradeVo");
			if (pubUpgradeVo != null && pubUpgrade.getIsWebCheck() != null
					&& YesNoEnum.YES.getCode() == pubUpgrade.getIsWebCheck().intValue()) {
				result.put("pubUpgradeVo", pubUpgradeVo);
				result.setCode(RespEnum.OK.getCode());
			}
		}
		return result;
	}

	private boolean isLegalRequest(HttpServletRequest request) {
		/*
		String auth = request.getHeader("qquantech2016");
		if (StringUtil.isBlank(auth) || !"tech@xfquanquan.com".equals(auth)) {
			return false;
		}
		*/
		return true;
	}

	private void sendErrorMsg(HttpServletResponse response, RespEnum type) throws IOException {
		Result result = new Result();
		result.setCode(type.getCode());
		result.setMsg(type.getDesc());
		String resultStr = JsonUtil.toJson(result);
		response.setHeader("Content-Type", "application/json; charset=" + CoreConst.DEFAULT_CODETYPE);
		PrintWriter writer = response.getWriter();
		writer.write(resultStr);
		writer.flush();
	}

	private void sendErrorMsg4Upgrade(HttpServletResponse response, RespEnum type, Result dataResult)
			throws IOException {
		Result result = new Result();
		result.setCode(type.getCode());
		result.setMsg(type.getDesc());
		result.put("pubUpgradeVo", dataResult.get("pubUpgradeVo"));
		String resultStr = JsonUtil.toJson(result);
		response.setHeader("Content-Type", "application/json; charset=" + CoreConst.DEFAULT_CODETYPE);
		PrintWriter writer = response.getWriter();
		writer.write(resultStr);
		writer.flush();
	}

	/**
	 * 生成请求id
	 * 
	 * @return
	 */
	private String buildRequestId() {
		String reqId = StringUtil.generateUUID().replaceAll("-", "");
		return reqId;
	}

	/**
	 * 打印参数
	 *
	 * @param request
	 */
	private void printRequest(HttpServletRequest request) {
		String paramsStr = getReqParams(request);
		StringBuffer requestURL = request.getRequestURL();
		if (!StringUtil.isBlank(paramsStr)) {
			requestURL.append("?" + paramsStr);
		}
		LOG.info("header={}", getHeader(request));
		LOG.info("url={}", requestURL);
	}

	@SuppressWarnings("rawtypes")
	private String getReqParams(HttpServletRequest request) {
		Map<String, String[]> map = request.getParameterMap();
		Set keSet = map.entrySet();
		StringBuffer paramStringBuffer = new StringBuffer();
		for (Iterator itr = keSet.iterator(); itr.hasNext();) {
			Map.Entry me = (Map.Entry) itr.next();
			Object key = me.getKey();
			Object v = me.getValue();
			String[] value = new String[1];
			if (v instanceof String[]) {
				value = (String[]) v;
			} else {
				value[0] = v.toString();
			}
			for (int k = 0; k < value.length; k++) {
				String str = value[k];
				if (hiddenKeys.contains(key)) {
					str = "_";
				}
				paramStringBuffer.append("&" + key + "=" + str);
			}
		}
		return paramStringBuffer.toString();
	}

	private Map<String, String> getHeader(HttpServletRequest request) {
		Map<String, String> header = Maps.newHashMap();
		header.put(HttpHeaders.REFERER, request.getHeader(HttpHeaders.REFERER));
		header.put(HttpHeaders.USER_AGENT, request.getHeader(HttpHeaders.USER_AGENT));
		header.put("VkReferer", request.getHeader("VkReferer"));
		header.put("ip", StringUtil.getClientIp(request));
		return header;
	}

	public void setAllowUrls(Set<String> allowUrls) {
		this.allowUrls = allowUrls;
	}
}